#ifndef _OH_WEAPON_H
#define	_OH_WEAPON_H
/*******************************************************************************
 ** Name: weapon.h                                                            **
 ** Description:                                                              **
 **                                                                           **
 ** Open Source Initiative (OSI) Approved 2-clause BSD License                **
 **                                                                           **
 **  Copyright (c) 2009-2010 Barry "Gian" James  <bjames@munixos.net>         **
 **  All rights reserved.                                                     **
 **                                                                           **
 **  Redistribution and use in source and binary forms, with or without       **
 **  modification, are permitted provided that the following conditions are   **
 **  met:                                                                     **
 **                                                                           **
 **  * Redistributions of source code must retain the above copyright notice, **
 **    this list of conditions and the following disclaimer.                  **
 **  * Redistributions in binary form must reproduce the above copyright      **
 **    notice, this list of conditions and the following disclaimer in the    **
 **    documentation and/or other materials provided with the distribution.   **
 **                                                                           **
 **  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS      **
 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED **
 ** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A           **
 ** PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT        **
 ** HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,    **
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED  **
 ** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR    **
 ** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    **
 ** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING      **
 ** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS        **
 ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.              **
 **                                                                           **
 ******************************************************************************/
// Modified $Date: 2011-10-22 02:09:07 +0000 (Sat, 22 Oct 2011) $ by $Author: gian.james $
#define _weapon_h_ID    "$Id: weapon.hpp 146 2011-10-22 02:09:07Z gian.james $"

#include <iostream>
#include <vector>
#include "object.hpp"
#include "traits.hpp"
#include "client.hpp"

#define AMMO_MAG    'M' 
#define AMMO_BELT   'B' 
#define AMMO_DRUM   'D'
#define AMMO_SINGLE 'S'

enum class AmmoType : uint8_t {
    FMJ, JHP, AP, API, HEI, Flechette, LTL, Buckshot,
    Concussion, Blank, Smoke, Flare, Incendiary, CS,
    Sabot, Frangible,
    max
};


//! @class Ammo
//! @brief All ammo information is managed by Ammo objects themselves.
class Ammo : public WorldObject
{
public:
    Ammo(std::string s):WorldObject(OType::Ammo,s) { type = AmmoType::FMJ; container = AMMO_MAG; rounds = 18; }
    Ammo(AmmoType,char,int);

    static const char *  Type(AmmoType);
    static const char *  TypeAbbr(AmmoType);

    void		FireRound() { --rounds; }
    void		FireRound(uint8_t burst) { rounds -= burst; }

    AmmoType    type;
    char        container;
    int         rounds;
    id_t		ammo;	//! from ammo DB table
};

//! The two top-level types of damage.
enum class DmgType : uint8_t {
    Lethal,     //!< Lethal damage can kill you
    NonLethal   /*!< Non-lethal damage can knock you out */
};

enum class WpnDamage { Ballistic, Piercing, Slashing, Bludgeoning, Bang };
enum class WpnClass :uint8_t { Melee, Ranged };
enum class WpnHands { One, Two };
enum class WpnType : uint8_t {
    Improvised, Axe, Mace, Sword, Spear, Nunchuk, Knife,
    Knuckles, Club, ExoticMelee,

    // Maybe break Handgun down into Holdout, Revolver, ACP, etc
    Handgun, AssaultRifle, BoltRifle, SniperRifle, Shotgun,
    Submachinegun, Machinegun, Explosive, Hurled,
    ExoticRanged,
    max
};

enum class WpnFireRate : uint8_t { Safety, Single, Burst, Auto };

// Trait flags
#define FLAG_TRAIT_WPN_AP        0x00000001	//!< armor piercing
#define FLAG_TRAIT_WPN_BAL       0x00000002	//!< balanced
#define FLAG_TRAIT_WPN_DR        0x00000004	//!< damage reduction
#define FLAG_TRAIT_WPN_DEP       0x00000008	//!< dependable
#define FLAG_TRAIT_WPN_DUR       0x00000010	//!< durable
#define FLAG_TRAIT_WPN_ER        0x00000020	//!< extended range
#define FLAG_TRAIT_WPN_FRL       0x00000040	//!< fast reload
#define FLAG_TRAIT_WPN_FLA       0x00000080	//!< flamable
#define FLAG_TRAIT_WPN_FRA       0x00000100	//!< frangible
#define FLAG_TRAIT_WPN_GUI       0x00000200 //!< guided
#define FLAG_TRAIT_WPN_LR        0x00000400	//!< long range
#define FLAG_TRAIT_WPN_NV        0x00000800	//!< nigh vision
#define FLAG_TRAIT_WPN_OBA       0x00001000	//!< off balance
#define FLAG_TRAIT_WPN_REL       0x00002000	//!< reliable
#define FLAG_TRAIT_WPN_SR        0x00004000	//!< short range
#define FLAG_TRAIT_WPN_SRL       0x00008000	//!< slow reload
#define FLAG_TRAIT_WPN_SPL       0x00010000
#define FLAG_TRAIT_WPN_VOL       0x00020000
#define FLAG_TRAIT_WPN_URL       0x00040000
#define FLAG_TRAIT_WPN_UPG       0x00080000	//!< upgradable
#define FLAG_TRAIT_WPN_ACC       0x00100000   // accurate
#define FLAG_TRAIT_WPN_IMP       0x00200000   // imprecise
#define FLAG_TRAIT_WPN_BLK       0x00400000   // bulky
#define FLAG_TRAIT_WPN_DIS       0x00800000   // discreet
#define FLAG_TRAIT_WPN_SUP       0x01000000   // suppressed
#define FLAG_TRAIT_WPN_NSY       0x02000000   // noisy
#define FLAG_TRAIT_WPN_THB       0x04000000   // threaded barrel
#define FLAG_TRAIT_WPN_CMP       0x08000000   // composite

//! @brief Base class for all weapons in the game.
class Weapon : public WorldObject
{
public:
    Weapon(std::string n);
    Weapon(std::string,WpnType,WpnHands,WpnClass,WpnDamage,OType);
    Weapon(const Weapon& orig);
    virtual ~Weapon();

    virtual std::string TypeToStr() { return "Weapon"; }
    inline bool IsLethal() { if (wdmg == WpnDamage::Bludgeoning) return false; else return true; }


     WpnType      WeaponType() const { return wtype; }
     WpnHands     Hands() const { return hands; }
     WpnClass     WeaponClass() const { return wclass; }
     WpnDamage    WeaponDamage() const { return wdmg; }
     ushort   Range() const { return range; }
     int      Cost() const { return cost; }
     Trait *  Traits() const { return traits; }
     WpnType SubType() const { return wtype; }

    static std::string  SubTypeToStr(WpnType);
    static std::string  HandsToStr(WpnHands h)
    { if (h == WpnHands::One) return "One handed"; else return "Two handed"; }
    static inline std::string  WpnClassToStr(WpnClass);
    static inline std::string DamageType(WpnDamage dt);

    std::string    FQType();     // Fully-Qualified Object Type

    inline void     SetWeaponType(WpnType wt) { wtype = wt; }
    inline void     SetHands(WpnHands h) { hands = h; }
    inline void     SetWeaponClass(WpnClass c) { wclass = c; }
    inline void     SetWeaponDamage(WpnDamage d) { wdmg = d; }
    inline void     SetRange(ushort r) { range = r; }
    inline void     SetCost(int c) { cost = c; }
    inline void     AddTrait(Trait * t);
    inline void     SetDamage(uint8 r, uint8 n) { dmg.rolls = r; dmg.num = n; }
    inline Dice     GetDamage() const { return dmg; }
    
    uint32_t &		TraitFlags() { return ftraits; }
    void			SetTraitFlags(uint32_t f) { BMSET(ftraits,f); }
    void			ClearTraitFlags(uint32_t f) { BMCLR(ftraits,f); }

protected:
    WpnType     wtype;
    WpnHands    hands;
    WpnClass    wclass;
    WpnDamage   wdmg;
    ushort      range;  //!< range increment (ft)
    int         cost;
    Trait *     traits;
    uint32_t	ftraits;
    Dice        dmg;
    int			error;	//!< error range (0 - int)
};

//! @brief Represents all ranged weapons in the game.
class RangedWeapon : public Weapon
{
public:
    RangedWeapon(std::string n); //!< creation via objfactory
    RangedWeapon(std::string,WpnType,WpnHands,WpnFireRate);

    inline int  GetRecoil() const { return recoil; }
    inline void SetRecoil(int r) { recoil = r; }
    inline WpnFireRate GetFireRate() const { return rate; }
    void SetFireRate(WpnFireRate r);

    static std::string FireRate(WpnFireRate fr);
    int			Actionable(std::string cmd, Client * player);

    inline void AddAmmo(Ammo a) { ammo.push_back(a); }
private:
    int         recoil;     //!< str must be >=, and +5 > for full auto
    WpnFireRate rate;       //!< what the weapon is capable of doing
    WpnFireRate selector;   //!< The rate of fire selector switch
    std::vector<Ammo>   ammo;
    
};

//! @brief Represents all hand-held/melee weapons.
class MeleeWeapon : public Weapon
{
public:
    MeleeWeapon(std::string n);  //!< creation via objfactory
    MeleeWeapon(std::string n,WpnType t,WpnHands h,WpnDamage wd,int s,int d);

    inline int  StrReq() const { return minStr; }
    inline int  DexReq() const { return minDex; }
    int			Actionable(std::string cmd, Client * player);

private:
    int     minStr; //!< minimum STR to use
    int     minDex; /*!< minimum DEX to use */
};

#endif	/* _OH_WEAPON_H */

